/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sirtet.netplay;

import sirtet.netplay.server.GameRoom;
import java.util.Set;
import sirtet.GameAction;
import sirtet.GameBoard;
import sirtet.Player;
import sirtet.netplay.event.CommunicationDataEvent;
import sirtet.netplay.event.CommunicationEvent;
import sirtet.netplay.event.CommunicationListener;

/**
 * A player representing a remote player.  The actions come from network.
 * @author guangwei.zhu
 */
public class NetworkPlayer extends Player {

    protected Communicator communicator;
    private String gametype;
    private CommunicationListener listener = new CommunicationListener() {

        public void communicationDisconnected(CommunicationEvent evt) {
            // Communicator is disconnected. Cause a hierarchical destruction
            quit();
            NetworkPlayer.this.communicator = null;
            NetworkPlayer.this.actionListeners.clear();
            if (getBoard() != null) {
                getBoard().unregisterPlayer(NetworkPlayer.this);
            }
        }

        public void communicationDataReceived(CommunicationDataEvent evt) {
            // Default action
            String data = evt.data;
            GameAction action = GameAction.fromString(data);
            if (action == null) {
                try {   // Not a player-aware message
                    if (!preprocess(data)) {    // First handle with local handler
                        // If not handled, pass to global handler
                        ClientResponse.respond(NetworkPlayer.this, data);
                    }
                } finally {
                    return;
                }
            }

            // By default, only process actions that match my ID
            if (action.actor.equals(NetworkPlayer.this.id())) {
                // Hand it to the GameBoard
                NetworkPlayer.this.invokeAction(action);
            }
        }
    };

    public NetworkPlayer(String playerID, String gametype, boolean ismain) {
        super(playerID, gametype, ismain);
    }

    protected NetworkPlayer(Player innerPlayer, Communicator comm) {
        super(innerPlayer);

        this.communicator = comm;
        this.setCommunicator(comm);
    }

    public NetworkPlayer(String playerID, String gametype, boolean ismain, Communicator comm) {
        super(playerID, gametype, ismain);

        this.communicator = comm;
        this.setCommunicator(comm);
    }

    public void setCommunicator(Communicator comm) {
        if (comm == null) {
            throw new NullPointerException();
        }

        if (this.communicator != comm) {
            this.communicator.removeCommunicationListener(listener);
        }

        this.communicator = comm;
        comm.addCommunicationListener(listener);
    }

    public Communicator getCommunicator() {
        return this.communicator;
    }

    /**
     * Choose the preferred GameBoard to join in.  The default choice is the
     * first one in the offered set.
     * @param boards the set of boards that are offered as available choices
     * @return the preferred board which the player wants to join in.
     */
    public GameBoard choose(
            Set<GameBoard> boards) {
        try {
            return boards.iterator().next();
        } catch (Exception ex) {
            return null;
        }

    }

    /**
     * Choose the preferred GameRoom to join in.  The default choice is the
     * first one in the offered set.
     * @param rooms the set of rooms that are offered as available choices
     * @return the preferred room which the player wants to join in.
     */
    public GameRoom choose(Set<GameRoom> rooms) {
        try {
            return rooms.iterator().next();
        } catch (Exception ex) {
            return null;
        }

    }

    /**
     * Preprocess the network message and invoke appropriate event if the
     * message indicates an event other than a game action. (e.g. QUIT or
     * STOP, etc.)
     * @param data the network message received
     * @return true if the message is processed, implying that it is a
     * non-game action, and thus should not be further handed to the GameBoard;
     * false to indicate that it be handed on to the board
     */
    protected boolean preprocess(String data) {
        if (data.equals(ServerResponse.QUIT)) {
            this.quit();
            return true;
        } else if (data.equals(ServerResponse.START)) {
            this.setEnabled(true);
            return true;
        } else if (data.equals(ServerResponse.STOP)) {
            this.setEnabled(false);
            return true;
        } else if (data.equals(ClientResponse.READY)) {
            this.setReady(true);
            return true;
        }

        return false;
    }
}
